package com.jse.jdbc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

public class Cnd {

	record Four<A,B,C,D>(A a,B b,C c,D d){}
	
	private List<Object> wheres=new ArrayList<>();
	private List<Object> params=new ArrayList<>();
//	private StringBuilder sb=new StringBuilder();
	Map pager;
	String orderBy;
	String groupBy;
	private String sql;
	private boolean notcount=true;
	public Cnd() {}
	
	public static Cnd where(String column,String op,Object val){
		var cnd=new Cnd();
		cnd.add("where",column,op,val);
		return cnd;
	}
	public static Cnd where(String where){return wrap(where);}
	public static Cnd wrap(String where){
		var cnd=new Cnd();
		if(where.toLowerCase().indexOf("where")==-1) {
			cnd.add(" where "+where);
		}else {
			cnd.add(where);
		}
		return cnd;
	}
	public static Cnd where(Map map){
		var cnd=new Cnd();
		map.forEach((k,v)->{
			String n=k.toString();
			String[] ns=n.split(" ");
			if(ns.length==1) {
				cnd.and(n,"=",v);
			}else if(ns.length==2) {
				cnd.and(ns[0],ns[1],v);
			}else{
				cnd.add(ns[0],ns[1],ns[2],v);
			}
		});
		return cnd;
	}

	public Cnd and(String column, String op, Object val) {
		if(wheres.isEmpty())add("where", column, op, val);
		else add("and", column, op, val);
		return this;
	}
	public Cnd and(String s) {
		wheres.add(" and "+s);
		return this;
	}
	public Cnd or(String column, String op, Object val) {
		add("or", column, op, val);return this;
	}
	public Cnd or(String s) {wheres.add(" or "+s);return this;}
	public Cnd add(String n, String column, String op, Object val) {
		if(op.equalsIgnoreCase("in")) {
			if(val instanceof Map c) {val=c.values().toArray();}
			if(val instanceof Collection c) {val=c.toArray();}
			if(val instanceof String s) {
				if(s.trim().startsWith("(")) {
					wheres.add(n+" "+column+" in "+s);
				}else {
					val=s.split(",");
				}
			}
			if(val.getClass().isArray()) {
				var arr=(Object[])val;
				StringJoiner cname=new StringJoiner(",","(",")");
				for (int i = 0; i < arr.length; i++) {
					cname.add("?");params.add(arr[i]);
				}
				wheres.add(new Four(n,column,op,cname));
			}
		}else if(op.equalsIgnoreCase("between")) {
			if(val instanceof String s) {if(s.indexOf(",")!=-1)val=s.split(",");}
			if(val instanceof Map c) {val=c.values().toArray();}
			if(val instanceof Collection c) {val=c.toArray();}
			if(val.getClass().isArray()) {
				var arr=(Object[])val;
				params.add(arr[0]);params.add(arr[1]);
				wheres.add(" "+n+" "+column+" between ? and ?");
			}
		}else {
			if(val instanceof String s) {
				String x=s.trim();
				if(x.startsWith(":")) {
					wheres.add(n+" "+column+" "+op+" "+x.substring(1));
				}else {
					wheres.add(new Four(n,column,op,'?'));
					params.add(val);
				}
			}else {
				wheres.add(new Four(n,column,op,'?'));
				params.add(val);
			}
		}
		
		return this;
	}
	public Cnd add(String s) {
		wheres.add(s);
		return this;
	}
	public Cnd pager(Map pager) {
		this.pager=pager;
		return this;
	}
	public Map pager() {return pager;}
	public String orderBy() {return orderBy;}
	public Cnd asc(String s) {
		orderBy=" order by "+s;
		return this;
	}
	public Cnd desc(String s) {
		orderBy=" order by "+s+" desc";
		return this;
	}
	public Cnd orderBy(String orderBy) {
		this.orderBy=orderBy;
		return this;
	}
	public Cnd groupBy(String groupBy) {
		if(groupBy.toLowerCase().contains("group")) {
			this.groupBy=groupBy;
		}else {
			this.groupBy=" group by "+groupBy;
		}
		return this;
	}
	public Cnd sql(String sql) {
		this.sql=sql;
		return this;
	}
	public Cnd addParam(Object arg) {params.add(arg);return this;}
	public Cnd addParam(Object[] a){if(a!=null&&a.length>0)return addParam(Arrays.asList(a));return this;}
	public Cnd addParam(Collection<?> a){if(a!=null&&a.size()>0)params.addAll(a);return this;}
	public Cnd insertParam(Object arg) {params.addFirst(arg);return this;}
	public Cnd insertParam(Object[] a){if(a!=null&&a.length>0)return insertParam(Arrays.asList(a));return this;}
	public Cnd insertParam(Collection<?> a){if(a!=null&&a.size()>0)params.addAll(0,a);return this;}
	
	public void notcount(boolean notcount) {
		this.notcount=notcount;
	}
	
	public String sql() {
		return sql;
	}
	public String sql(String sql,Object...args) {
		if(args!=null&&args.length>0)params.addAll(Arrays.asList(args));
		return sql;
	}
	
	public List<Object> getParams(){return params;}
	
	@Override
	public String toString() {
		if(sql==null||!notcount) {
			StringBuilder sb=new StringBuilder();
			wheres.forEach(x->{
				if(x instanceof Four t) {
					sb.append(" ").append(t.a).append(" ").append(t.b).append(" ").append(t.c).append(" ").append(t.d);
				}else {
					sb.append(" ").append(x);
				}
			});
			if(groupBy!=null)sb.append(groupBy);
			if(notcount&&orderBy!=null)sb.append(orderBy);
			if(notcount&&pager!=null)sb.append(Jdbc.paginationSQL(pager));
			sql=sb.toString();
		}
		return sql;
	}

	public static void main(String[] args) {
		System.out.println(Cnd.where("password","=",0)
				.add("and (code='"+1+"' or phone='"+2+"')"));
	}
}
